%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "node.h"

	Node* opr(int name, int num, ...);
	Node* set_index(int value);
	Node* set_content(int value);

	void freeNode(Node* p);
	int exeNode(Node* p);

	int yylexeNode(void);
	void yyerror(char* s);

	int Var[26];

%}

%union {
	int iValue;
	char sIndex;
	Node *nPtr;
};

%token <iValue> VARIABLE
%token <sIndex> INTEGER
%token WHILE IF PRINT
%nonassoc	IFX
%nonassoc ELSE
%left AND OR GE	LE EQ NE '>' '<'
%left '+' '-'
%left '*' '/' '%'
%nonassoc	UMINUS
%type <nPtr>	stmt expr stmt_list

%%

program:
	function { exit(0); }
	|
	;
function:
	function stmt { exeNode($2); freeNode($2); }
	|
	;
stmt:
	';' { opr(';', 2, NULL, NULL); }
	| expr ';' { $$ = $1; }
	| PRINT expr ';' { $$ = opr(PRINT, 1, $2); }
	| VARIABLE '=' expr ';' { $$ = opr('=', 2, set_index($1), $3); }
	| WHILE '(' expr ')' stmt { $$ = opr(WHILE, 2, $3, $5); }
	| IF '(' expr ')' stmt %prec IFX { $$ = opr(IF, 2, $3, $5); }
	| IF '(' expr ')' stmt ELSE stmt %prec ELSE { $$ = opr(IF, 3, $3, $5, $7); }
	| '{' stmt_list '}' { $$ = $2; }
	;
stmt_list:
	stmt { $$ = $1; }
	| stmt_list stmt { $$ = opr(';', 2, $1, $2); }
	;
expr:
	INTEGER { $$ = set_content($1); }
	| VARIABLE { $$ = set_index($1); }
	| '-' expr %prec UMINUS { $$ = opr(UMINUS, 1, $2); }
	| expr '+' expr { $$ = opr('+', 2, $1, $3); }
	| expr '-' expr { $$ = opr('-', 2, $1, $3); }
	| expr '*' expr { $$ = opr('*', 2, $1, $3); }
	| expr '/' expr { $$ = opr('/', 2, $1, $3); }
	| expr '<' expr { $$ = opr('<', 2, $1, $3); }
	| expr '>' expr { $$ = opr('>', 2, $1, $3); }
	| expr GE expr { $$ = opr(GE, 2, $1, $3); }
	| expr LE expr { $$ = opr(LE, 2, $1, $3); }
	| expr NE expr { $$ = opr(NE, 2, $1, $3); }
	| expr EQ expr { $$ = opr(EQ, 2, $1, $3); }
	| expr AND expr { $$ = opr(AND, 2, $1, $3); }
	| expr OR expr { $$ = opr(OR, 2, $1, $3); }
	| '(' expr ')' { $$ = $2; }
	;

%%

#define SIZE_OF_NODE ((char*)&p->content - (char*)p)

Node* set_content(int value) {
	Node* p;
	size_t sizeNode;
	sizeNode = SIZE_OF_NODE + sizeof(int);
	if ((p = malloc(sizeNode)) == NULL) {
		yyerror(" out of memory ");
	}

	p->type = TYPE_CONTENT;
	p->content = value;
	return p;
}

Node* set_index(int value) {
	Node *p;
	size_t sizeNode;
	sizeNode = SIZE_OF_NODE + sizeof(int);
	if ((p = malloc(sizeNode)) == NULL) {
		yyerror(" out of memory ");
	}
	p->type = TYPE_INDEX;
	p->index = value;
	return p;
}

Node *opr(int name, int num, ...) {
	va_list valist;
	Node* p;
	size_t sizeNode;
	int i;
	sizeNode = SIZE_OF_NODE + sizeof(OpNode) + (num - 1) * sizeof(Node*);
	if ((p=malloc(sizeNode)) == NULL) {
		yyerror(" out of memory ");
	}
	p->type = TYPE_OP;
	p->op.name = name;
	p->op.num = num;
	va_start(valist, num);
	for(i = 0; i < num; ++i) {
		p->op.node[i] = va_arg(valist, Node*);
	}
	va_end(valist);
	return p;
}

void freeNode(Node* p) {
	int i;
	if (!p) return;
	if (p->type == TYPE_OP) {
		for (i = 0; i < p->op.num; ++i)
			freeNode(p->op.node[i]);
	}
	free(p);
}

void yyerror(char* s) {
	fprintf(stdout, "%s\n", s);
}


int main() {
	yyparse();
	return 0;
}


